import json
import socket
import threading
import time


# 添加自己的业务Operator
class BlenderMCPServer:
    def __init__(self, host='localhost', port=9876):
        self.host = host
        self.port = port
        self.running = False
        self.socket = None
        self.client = None
        self.server_thread = None

    def start(self):
        self.running = True
        self.server_thread = threading.Thread(target=self._run_server)
        self.server_thread.daemon = True
        self.server_thread.start()
        print(f"BlenderMCP server started on {self.host}:{self.port}")

    def stop(self):
        self.running = False
        if self.socket:
            self.socket.close()
        if self.client:
            self.client.close()
        print("BlenderMCP server stopped")

    def _run_server(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        try:
            self.socket.bind((self.host, self.port))
            self.socket.listen(1)
            self.socket.settimeout(1.0)  # Add a timeout for accept

            while self.running:
                try:
                    self.client, address = self.socket.accept()
                    print(f"Connected to client: {address}")

                    while self.running:
                        try:
                            # Set a timeout for receiving data
                            self.client.settimeout(15.0)
                            data = self.client.recv(4096)
                            if not data:
                                print("Empty data received, client may have disconnected")
                                break

                            try:
                                print(f"Received data: {data.decode('utf-8')}")
                                command = json.loads(data.decode('utf-8'))
                                response = self.execute_command(command)
                                print(
                                    f"Sending response: {json.dumps(response)[:100]}...")  # Truncate long responses in log
                                self.client.sendall(json.dumps(response).encode('utf-8'))
                            except json.JSONDecodeError:
                                print(f"Invalid JSON received: {data.decode('utf-8')}")
                                self.client.sendall(json.dumps({
                                    "status": "error",
                                    "message": "Invalid JSON format"
                                }).encode('utf-8'))
                            except Exception as e:
                                print(f"Error executing command: {str(e)}")
                                import traceback
                                traceback.print_exc()
                                self.client.sendall(json.dumps({
                                    "status": "error",
                                    "message": str(e)
                                }).encode('utf-8'))
                        except socket.timeout:
                            print("Socket timeout while waiting for data")
                            continue
                        except Exception as e:
                            print(f"Error receiving data: {str(e)}")
                            break

                    self.client.close()
                    self.client = None
                except socket.timeout:
                    # This is normal - just continue the loop
                    continue
                except Exception as e:
                    print(f"Connection error: {str(e)}")
                    if self.client:
                        self.client.close()
                        self.client = None
                    time.sleep(1)  # Prevent busy waiting

        except Exception as e:
            print(f"Server error: {str(e)}")
        finally:
            if self.socket:
                self.socket.close()

    def execute_command(self, command):
        """Execute a Blender command received from the MCP server"""
        cmd_type = command.get("type")
        params = command.get("params", {})

        # Add a simple ping handler
        if cmd_type == "ping":
            print("Handling ping command")
            return {"status": "success", "result": {"pong": True}}
        else:
            return {
                "status": "error",
                "result": f"Unknown command type: {command.get('type')}"
            }
